package org.bedracket.pgeg.util;

import net.minecraft.advancements.Advancement;
import net.minecraft.advancements.AdvancementProgress;
import net.minecraft.core.BlockPos;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.item.ItemEntity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.enchantment.Enchantment;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Block;
import net.minecraftforge.registries.DeferredRegister;
import net.minecraftforge.registries.RegistryObject;
import org.bedracket.pgeg.PGEGMod;
import org.bedracket.pgeg.init.ModBlocks;
import org.bedracket.pgeg.init.ModEnchantments;
import org.bedracket.pgeg.init.ModItems;

import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

public class Helpers {

    public static final DeferredRegister<? extends Item> ITEM_LIST = ModItems.ITEMS;
    public static final DeferredRegister<? extends Block> BLOCK_LIST = ModBlocks.BLOCKS;
    public static final DeferredRegister<? extends Enchantment> ENCHANTMENT_LIST = ModEnchantments.ENCHANTMENTS;

    public static String namespace(String name) {
        return PGEGMod.MOD_ID + ":" + name;
    }

    public static ItemStack randomStack(Level level, Item drop, int min, int max) {
        return new ItemStack(drop, max - min > 0 ? level.getRandom().nextInt(max - min + 1) + min : min);
    }

    public static ItemStack randomStack(Level level, Item drop, int min, int max, int looting) {
        if (looting > 0) {
            return new ItemStack(drop, max+looting - min > 0
                    ? level.getRandom().nextInt(max+looting - min + 1)
                    + min : min);
        }else {
            return randomStack(level, drop, min, max);
        }
    }

    public static ItemStack stack(Level level, Item drop, int count, int looting) {
        return randomStack(level, drop, count, count, looting);
    }

    /**
     * A method that create a new ItemEntity
     * @param level the world taht ItemEntity generate
     * @param pos drop block pos
     * @param stack the origin ItemStack
     * @return a new Item Entity
     */
    public static ItemEntity itemEntity(Level level, BlockPos pos, ItemStack stack) {
        return new ItemEntity(level, pos.getX(), pos.getY(), pos.getZ(), stack);
    }

    /**
     * A method used to get Enchantments that PGEG mod registered
     * @return a set list of enchantments
     */
    public static Set<Enchantment> getEnchantments() {
        return ENCHANTMENT_LIST.getEntries().stream()
                .map(RegistryObject::get).collect(Collectors.toSet());
    }

    /**
     * A method used to get Blocks that PGEG mod registered
     * @return a set list of Blocks
     */
    public static Set<Block> getBlocks() {
        return BLOCK_LIST.getEntries().stream()
                .map(RegistryObject::get).collect(Collectors.toSet());
    }

    /**
     * A method used to get Items that PGEG mod registered
     * @return a set list of items
     */
    public static Set<Item> getItems() {
        return ITEM_LIST.getEntries().stream()
                .map(RegistryObject::get).collect(Collectors.toSet());
    }

    /**
     * Default {@link ResourceLocation}, except with a PGEG Mod namespace
     */
    public static ResourceLocation identifier(String name) {
        return new ResourceLocation(PGEGMod.MOD_ID, name);
    }

    /**
     * Use for create cool down of item
     * @param player the player who use it
     * @param item the items
     * @param ticks remain ticks
     */
    public static void addCoolDown(Player player, Item item, int ticks) {
        player.getCooldowns().addCooldown(item, ticks);
    }

    /**
     * Make the players obtain a advancement
     * @param player the player should get advancement
     * @param id the advancement id
     */
    public static void obtainAdvancement(Player player, String id) {
        if (player instanceof ServerPlayer serverPlayer) {
            Advancement advancement =
                    Objects.requireNonNull(serverPlayer.getServer())
                            .getAdvancements().getAdvancement(Helpers.identifier(id));
            assert advancement != null;
            AdvancementProgress progress = serverPlayer.getAdvancements()
                    .getOrStartProgress(advancement);
            if (!progress.isDone()) {
                for (String s : progress.getRemainingCriteria())
                    serverPlayer.getAdvancements().award(advancement, s);
            }
        }
    }
}
